package cn.dwy2002.task.impl;

import cn.dwy2002.task.mapper.TaskMapper;
import cn.dwy2002.task.mapper.TaskTypeRelMapper;
import cn.dwy2002.task.service.ITaskService;
import cn.dwy2002.task.service.ITaskTypeRelService;
import cn.dwy2002.task.service.TaskStateMachine;
import cn.hutool.core.bean.BeanUtil;
import com.aliyun.oss.ServiceException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.dwy2002.common.Result;
import com.dwy2002.common.exception.EmptyIdException;
import com.dwy2002.common.utils.JwtUtil;
import com.dwy2002.common.utils.Validator;
import com.dwy2002.enums.Status;
import com.dwy2002.enums.TaskState;
import com.dwy2002.pojo.bo.TaskToUserMessageBO;
import com.dwy2002.pojo.bo.UserToTaskMessageBO;
import com.dwy2002.pojo.dto.task.TaskDTO;
import com.dwy2002.pojo.dto.task.TaskPageDTO;
import com.dwy2002.pojo.dto.task.UpdateProgressDTO;
import com.dwy2002.pojo.po.task.Task;
import com.dwy2002.pojo.po.task.TaskType;
import com.dwy2002.pojo.po.task.TaskTypeRel;
import com.dwy2002.pojo.po.users.Users;
import com.dwy2002.pojo.vo.task.TaskVO;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

import static com.dwy2002.common.Result.*;
import static com.dwy2002.common.utils.JsonConversionUtils.convertToType;
import static com.dwy2002.common.utils.Utils.*;
import static com.dwy2002.enums.rabbit.TaskRabbitConstants.*;

/**
 * @author 杜伟毅
 * @version 1.0
 * @since 2025/07/14
 */
@Service
@RequiredArgsConstructor
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements ITaskService {
    private final ITaskTypeRelService taskTypeRelService;
    private final TaskTypeRelMapper taskTypeRelMapper;
    private final RabbitTemplate rabbitTemplate;
    private final TaskStateMachine stateMachine;
    private final JwtUtil jwtUtil;

    /**
     * 查询任务分页信息
     * <p>
     * 查询：可按任务标题、描述搜索
     * <p>
     * 排序：可按创建时间、更新时间、截止时间进行排序
     * <p>
     * 分类：可按任务优先级、任务状态进行分类
     *
     * @param dto 任务分页查询DTO
     * @return 分页结果
     * @author 杜伟毅
     * @since 2025/7/14 0014 15:35
     */
    @Override
    public Result<IPage<TaskVO>> getTaskPage(TaskPageDTO dto) {
        Validator.of(dto)
                .mustSatisfy(isPageNull(dto.getPageNo(), dto.getPageSize()), "请传入分页数据")
                .mustSatisfy(isPageZero(dto.getPageNo(), dto.getPageSize()), "分页数据不能为0")
                .validate();

        // 创建分页对象
        Page<TaskVO> page = new Page<>(dto.getPageNo(), dto.getPageSize());

        // 执行自定义分页查询
        IPage<TaskVO> voPage = this.baseMapper.selectTaskVOPage(page, dto);
        return success(voPage);
    }

    /**
     * 创建任务
     *
     * @param dto 任务数据传输对象
     * @return 操作结果
     * @author 杜伟毅
     * @since 2025/7/14 0014 15:35
     */
    @Override
    public Result<Void> createTask(TaskDTO dto) {
        Validator.of(dto)
                .notEmpty(TaskDTO::getTitle, "任务标题不能为空")
                .notNull(TaskDTO::getPriority, "优先级不能为空")
                .mustSatisfy(!Task.TaskPriorityEnum.isValidPriority(dto.getPriority()), "优先级不在范围内，请重新选择")
                .notNull(TaskDTO::getDueDate, "任务截止日期不允许为空")
                .notEmpty(TaskDTO::getAssigneeId, "责任人不允许为空")
                .validate();
        Task task = BeanUtil.copyProperties(dto, Task.class);

        String taskId = IdWorker.get32UUID();

        //插入创建人（当前登陆的用户）
        String userId = jwtUtil.parseToken(getToken(), Users.class).getId();
        task.setId(taskId);
        task.setCreatorId(userId);
        //插入状态1-已创建
        task.setPriority(TaskState.PUBLISHED.getCode());
        boolean save = save(task);

        //插入任务类型
        taskTypeRelService.addTypeToTask(taskId, dto.getTypeId());

        return saveResult(save, "任务创建成功", "任务创建失败");
    }

    /**
     * 批量删除任务（逻辑删除）
     *
     * @param ids 任务ID列表
     * @return 操作结果
     * @author 杜伟毅
     * @since 2025/7/14 0014 15:35
     */
    @Override
    public Result<Void> deleteTasks(List<String> ids) {
        if (isListEmpty(ids)) throw new EmptyIdException("deleteTasks");

        List<Task> tasks = list(new LambdaQueryWrapper<Task>().in(Task::getId, ids));
        if (isListEmpty(ids)) return fail(Status.BAD_REQUEST, "未找到可删除的任务");

        List<String> validaIds = tasks.stream()
                .map(Task::getId)
                .toList();

        boolean remove = removeByIds(validaIds);

        taskTypeRelService.removeTypeFromTask(ids);

        return handleResult(remove, "任务删除成功", "任务删除失败");
    }

    /**
     * 更新任务信息
     *
     * @param dto 任务数据DTO
     * @return 操作结果
     * @author 杜伟毅
     * @since 2025/7/14 0014 15:35
     */
    @Override
    public Result<Void> updateTask(TaskDTO dto) {
        Validator.of(dto)
                .notEmpty(TaskDTO::getId, "ID不允许为空")
                .notEmpty(TaskDTO::getTitle, "任务标题不能为空")
                .notNull(TaskDTO::getPriority, "优先级不能为空")
                .mustSatisfy(!Task.TaskPriorityEnum.isValidPriority(dto.getPriority()), "优先级不在范围内，请重新选择")
                .notNull(TaskDTO::getDueDate, "任务截止日期不允许为空")
                .notEmpty(TaskDTO::getAssigneeId, "责任人不允许为空")
                .notEmpty(TaskDTO::getTypeId, "任务类型不允许为空")
                .validate();

        Task task = getById(dto.getId());

        if (ObjectUtils.isEmpty(task)) return fail(Status.BAD_REQUEST, "任务不存在");

        LambdaUpdateWrapper<Task> luw = new LambdaUpdateWrapper<>();
        luw.eq(Task::getId, dto.getId())
                .set(Task::getTitle, dto.getTitle())
                .set(!Objects.equals(task.getDescription(), dto.getDescription()), Task::getDescription, dto.getDescription())
                .set(!Objects.equals(task.getPriority(), dto.getPriority()), Task::getPriority, dto.getPriority())
                .set(!Objects.equals(task.getAssigneeId(), dto.getAssigneeId()), Task::getAssigneeId, dto.getAssigneeId());
        boolean save = update(luw);

        //修改任务类型
        taskTypeRelService.updateTypeToTask(dto.getId(), dto.getTypeId());

        return saveResult(save, "任务更新成功", "任务更新失败");
    }

    /**
     * 获取任务详情
     *
     * @param id 任务ID
     * @return 任务详情视图对象
     * @author 杜伟毅
     * @since 2025/7/14 0014 15:35
     */
    @Override
    public Result<TaskVO> getTaskDetail(String id) {
        if (isEmptyOrNull(id)) return fail(Status.BAD_REQUEST, "ID不允许为空");
        Task task = getById(id);
        if (ObjectUtils.isEmpty(task)) return fail(Status.BAD_REQUEST, "任务不存在");

        //查询并插入责任人昵称与创建人昵称
        TaskVO taskVO = BeanUtil.copyProperties(task, TaskVO.class);
        taskVO.setAssigneeNickname(Db.getById(task.getAssigneeId(), Users.class).getNickname());
        taskVO.setCreatorNickname(Db.getById(task.getCreatorId(), Users.class).getNickname());

        //任务类型名称
        String typeId = taskTypeRelMapper.selectOne(new LambdaQueryWrapper<TaskTypeRel>().eq(TaskTypeRel::getTaskId, id)).getTypeId();
        taskVO.setTaskTypeName(Db.getById(typeId, TaskType.class).getName());

        return success(taskVO);
    }

    /**
     * 更新任务进度状态
     *
     * @param dto 任务进度更新信息
     * @return 操作结果
     * @author 杜伟毅
     * @since 2025/7/14 0014 15:35
     */
    @Override
    public Result<Void> updateTaskProgress(UpdateProgressDTO dto) {
        Validator.of(dto)
                .notEmpty(UpdateProgressDTO::getId, "ID不允许为空")
                .notNull(UpdateProgressDTO::getProgress, "任务状态不允许为空")
                .mustSatisfy(Task.TaskPriorityEnum.isValidPriority(dto.getProgress()), "任务状态无效")
                .validate();

        // 1. 获取任务当前状态
        Task task = getById(dto.getId());

        // 2. 验证状态转换
        if (!stateMachine.canTransit(task.getProgress(), dto.getProgress())) {
            return fail(Status.BAD_REQUEST, String.format("无法从[%s]转换到[%s]",
                    TaskState.fromCode(task.getProgress()).getDescription(),
                    TaskState.fromCode(dto.getProgress()).getDescription()));
        }

        // 3. 执行状态转换
        LambdaUpdateWrapper<Task> luw = new LambdaUpdateWrapper<Task>()
                .set(Task::getProgress, dto.getProgress());
        boolean update = update(luw);

        // 4. 触发状态变更事件
//        handleStateTransition(task, currentState, targetState);

        return handleResult(update, "状态更新成功", "状态更新失败");
    }

    /**
     * 返回员工的任务(员工自己查)
     *
     * @author 杜伟毅
     * @since 2025/7/21 0021 8:58
     */
    @Override
    public Result<List<TaskVO>> findTasksByEmployee() {
        return findTasksByEmployee(jwtUtil.parseToken(getToken(), Users.class).getId());
    }

    /**
     * 返回员工的任务(店长查)
     *
     * @param userId 用户id
     * @author 杜伟毅
     * @since 2025/7/21 0021 8:58
     */
    @Override
    public Result<List<TaskVO>> findTasksByEmployee(String userId) {
        if (isEmptyOrNull(userId)) fail(Status.BAD_REQUEST, "ID不允许为空");
        List<TaskVO> tasks = this.baseMapper.findTasksByEmployee(userId);
        return success(tasks);
    }

    // 子方法：-----------------------------------------------------------------

/*
* 暂时不需要，等待后续扩展
*
* 方法作用说明：
状态变更响应：当任务进入特定状态时，执行该状态特有的业务逻辑。
业务解耦：将与状态相关的业务逻辑集中管理，而不是散落在服务层各处。
事件驱动：可视为状态变更事件后的回调处理，是触发后续业务的入口点。
*
*
典型应用场景（对应您代码中的例子）：
进入 ONGOING（进行中）状态：
通知相关人员任务已开始
启动计时逻辑（如开始计算工时）
生成任务启动日志
notifyTaskStarted(task); // 发送通知
*
*
进入 WAITING_REVIEW（等待审核）状态：
创建审核流程
通知审核人员
设置审核截止时间
createReviewRequest(task); // 创建审核请求
*
*
进入 COMPLETED（已完成）状态：
标记所有关联子任务完成
触发任务完结结算流程
更新项目进度统计
completeTask(task); // 完成任务的结算操作
*
*
设计优势：
可扩展性：新增状态类型时只需添加一个 case分支
可维护性：所有状态相关逻辑集中在一个方法中
可读性：清晰展示各状态对应的业务处理
*
*     private void handleStateTransition(Task task, TaskState from, TaskState to) {
        // 状态变更业务处理
        switch (to) {
            case ONGOING:
                notifyTaskStarted(task);
                break;
            case WAITING_REVIEW:
                createReviewRequest(task);
                break;
            case COMPLETED:
                completeTask(task);
                break;
            // 其他状态处理...
        }
    }
*
*
*
* */


    /**
     * 发送RabbitMQ请求,请求user模块返回任务模块所需的责任人昵称与创建人昵称
     *
     * @param assigneeId 责任人ID（关联user表）
     * @param creatorId  创建人ID
     * @author 杜伟毅
     * @since 2025/3/24 0024 22:44
     */
    private void sendUserToRabbitMQ(String assigneeId, String creatorId) {

        TaskToUserMessageBO bo = new TaskToUserMessageBO()
                .setAssigneeId(assigneeId)
                .setCreatorId(creatorId);

        rabbitTemplate.convertAndSend(
                TASK_TO_USER_REQUEST_EXCHANGE,
                TASK_TO_USER_REQUEST_ROUTING_KEY,
                bo);
    }

    /**
     * 子方法：接收用户数据（含超时）
     *
     * @author 杜伟毅
     * @since 2025/3/24 0024 22:49
     */
    private UserToTaskMessageBO UserToTaskDataWithTimeout() {
        // 注册回调监听器
        rabbitTemplate.setReplyTimeout(30000); // 30秒超时
        try {
            Object received = rabbitTemplate.receiveAndConvert(USER_TO_TASK_RESPONSE_QUEUE);
            return convertToType(received, new TypeReference<>() {
            });
        } catch (AmqpException e) {
            throw new ServiceException("数据响应超时");
        }
    }


}
